home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / DirectInput / DIConfig / flexcombobox.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  9.9 KB  |  477 lines

  1. //-----------------------------------------------------------------------------
  2. // File: flexcombobox.cpp
  3. //
  4. // Desc: Implements a combo box control similar to Windows combo box.
  5. //       CFlexComboBox is derived from CFlexWnd.  It is used by the page
  6. //       for player list and genre list.  When the combo box is open,
  7. //       CFlexComboBox uses a CFlexListBox for the list window.
  8. //
  9. // Copyright (C) Microsoft Corporation. All Rights Reserved.
  10. //-----------------------------------------------------------------------------
  11.  
  12. #include "common.hpp"
  13.  
  14.  
  15. CFlexComboBox::CFlexComboBox() :
  16.     m_nTextHeight(-1),
  17.     m_hWndNotify(NULL),
  18.     m_rgbText(RGB(255,255,255)),
  19.     m_rgbBk(RGB(0,0,0)),
  20.     m_rgbSelText(RGB(0,0,255)),
  21.     m_rgbSelBk(RGB(0,0,0)),
  22.     m_rgbFill(RGB(0,0,255)),
  23.     m_rgbLine(RGB(0,255,255)),
  24.     m_dwFlags(0),
  25.     m_dwListBoxFlags(0),
  26.     m_bInSelMode(FALSE),
  27.     m_nSBWidth(11),
  28.     m_hFont(NULL),
  29.     m_eCurState(FCBS_CLOSED),
  30.     m_OldSel(-1)
  31. {
  32. }
  33.  
  34. CFlexComboBox::~CFlexComboBox()
  35. {
  36. }
  37.  
  38. CFlexComboBox *CreateFlexComboBox(FLEXCOMBOBOXCREATESTRUCT *pcs)
  39. {
  40.     CFlexComboBox *psb = new CFlexComboBox;
  41.     
  42.     if (psb && psb->Create(pcs))
  43.         return psb;
  44.     
  45.     delete psb;
  46.     return NULL;
  47. }
  48.  
  49. BOOL CFlexComboBox::Create(FLEXCOMBOBOXCREATESTRUCT *pcs)
  50. {
  51.     if (this == NULL)
  52.         return FALSE;
  53.  
  54.     if (pcs == NULL)
  55.         return FALSE;
  56.  
  57.     if (pcs->dwSize != sizeof(FLEXCOMBOBOXCREATESTRUCT))
  58.         return FALSE;
  59.  
  60.     m_hWndNotify = pcs->hWndNotify ? pcs->hWndNotify : pcs->hWndParent;
  61.  
  62.     m_dwFlags = pcs->dwFlags;
  63.     m_dwListBoxFlags = pcs->dwListBoxFlags;
  64.  
  65.     SetFont(pcs->hFont);
  66.     SetColors(pcs->rgbText, pcs->rgbBk, pcs->rgbSelText, pcs->rgbSelBk, pcs->rgbFill, pcs->rgbLine);
  67.     m_nSBWidth = pcs->nSBWidth;
  68.     m_rect = pcs->rect;
  69.  
  70.     if (!CFlexWnd::Create(pcs->hWndParent, GetRect(pcs->rect), pcs->bVisible))
  71.         return FALSE;
  72.  
  73.  
  74.     return TRUE;
  75. }
  76.  
  77. void CFlexComboBox::OnPaint(HDC hDC)
  78. {
  79.     HDC hBDC = NULL, hODC = NULL;
  80.     CBitmap *pbm = NULL;
  81.  
  82.     if (!InRenderMode())
  83.     {
  84.         hODC = hDC;
  85.         pbm = CBitmap::Create(GetClientSize(), RGB(0,0,0), hDC);
  86.         if (pbm != NULL)
  87.         {
  88.             hBDC = pbm->BeginPaintInto();
  89.             if (hBDC != NULL)
  90.             {
  91.                 hDC = hBDC;
  92.             }
  93.         }
  94.     }
  95.  
  96.     InternalPaint(hDC);
  97.  
  98.     if (!InRenderMode())
  99.     {
  100.         if (pbm != NULL)
  101.         {
  102.             if (hBDC != NULL)
  103.             {
  104.                 pbm->EndPaintInto(hBDC);
  105.                 pbm->Draw(hODC);
  106.             }
  107.             delete pbm;
  108.         }
  109.     }
  110. }
  111.  
  112. void CFlexComboBox::SetSel(int i)
  113. {
  114.     m_ListBox.SelectAndShowSingleItem(i, TRUE);
  115. }
  116.  
  117. int CFlexComboBox::GetSel()
  118. {
  119.     return m_ListBox.GetSel();
  120. }
  121.  
  122. LPCTSTR CFlexComboBox::GetText()
  123. {
  124.     return m_ListBox.GetSelText();
  125. }
  126.  
  127. void CFlexComboBox::InternalPaint(HDC hDC)
  128. {
  129.     HGDIOBJ hPen = (HGDIOBJ)CreatePen(PS_SOLID, 1, m_rgbLine);
  130.     if (hPen != NULL)
  131.     {
  132.         HGDIOBJ    hOldPen = SelectObject(hDC, hPen);
  133.  
  134.         HGDIOBJ hBrush = (HGDIOBJ)CreateSolidBrush(m_rgbBk);
  135.         if (hBrush != NULL)
  136.         {
  137.             HGDIOBJ hOldBrush = SelectObject(hDC, hBrush);
  138.  
  139.             RECT rect = {0,0,0,0};
  140.             GetClientRect(&rect);
  141.             Rectangle(hDC, rect.left, rect.top, rect.right, rect.bottom);
  142.  
  143.             RECT arect = rect;
  144.  
  145.             arect.left = arect.right - (arect.bottom - arect.top);
  146.  
  147.             // If we are read-only, only draw the text in gray. No border, no arrow.
  148.             if (!GetReadOnly())
  149.             {
  150.                 MoveToEx(hDC, arect.left, arect.top, NULL);
  151.                 LineTo(hDC, arect.left, arect.bottom);
  152.             }
  153.  
  154.             rect.left++;
  155.             rect.top++;
  156.             rect.right = arect.left;
  157.             rect.bottom--;
  158.  
  159.             SetTextColor(hDC, m_rgbText);
  160.             SetBkMode(hDC, TRANSPARENT);
  161.  
  162.             LPTSTR lpText = (LPTSTR)GetText();
  163.             if (lpText)
  164.             {
  165.                 DrawText(hDC, lpText, -1, &rect, DT_NOPREFIX);
  166.             }
  167.  
  168.             SelectObject(hDC, hOldBrush);
  169.             DeleteObject(hBrush);
  170.  
  171.             if (!GetReadOnly())
  172.             {
  173.                 hBrush = (HGDIOBJ)CreateSolidBrush(m_rgbFill);
  174.                 if (hBrush != NULL)
  175.                 {
  176.                     SelectObject(hDC, hBrush);
  177.  
  178.                     InflateRect(&arect, -3, -3);
  179.                     DrawArrow(hDC, arect, TRUE, FALSE);
  180.  
  181.                     SelectObject(hDC, hOldBrush);
  182.                     DeleteObject(hBrush);
  183.                 }
  184.             }
  185.         }
  186.  
  187.         SelectObject(hDC, hOldPen);
  188.         DeleteObject(hPen);
  189.     }
  190. }
  191.  
  192. int CFlexComboBox::AddString(LPCTSTR str)
  193. {
  194.     return m_ListBox.AddString(str);
  195. }
  196.  
  197. LRESULT CFlexComboBox::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  198. {
  199.     RECT wrect = {-1, -1, -1, -1};
  200.     POINT point = {-1, -1};
  201.     BOOL bWithin = FALSE;
  202.  
  203.     switch (msg)
  204.     {
  205.         case WM_SIZE:
  206.             Invalidate();
  207.             SetRect();
  208.             return 0;
  209.  
  210.         case WM_FLEXLISTBOX:
  211.             assert(lParam == (LPARAM)(LPVOID)&m_ListBox);
  212.             switch (wParam)
  213.             {
  214.                 case FLBN_FINALSEL:
  215.                     StateEvent(FCBSE_UPLIST);
  216.                     break;
  217.                 case FLBN_CANCEL:
  218.                     StateEvent(FCBSE_DOWNOFF);
  219.                     break;
  220.             }
  221.             return 0;
  222.  
  223.         // make sure flexwnd doesn't do ANYTHING with our mouse messages
  224.         case WM_MOUSEMOVE:
  225.             // We initialize the tooltip to current selection text if the selected text is too long to fit.
  226.             RECT rect;
  227.             GetClientRect(&rect);
  228.             rect.right = rect.right - (rect.bottom - rect.top);
  229.             rect.left++;
  230.             rect.top++;
  231.             rect.bottom--;
  232.             RECT ResultRect;
  233.             ResultRect = rect;
  234.             HDC hDC;
  235.             hDC = CreateCompatibleDC(NULL);
  236.             if (hDC)
  237.             {
  238.                 LPTSTR lpText = (LPTSTR)GetText();
  239.                 if (lpText)
  240.                 {
  241.                     DrawText(hDC, lpText, -1, &ResultRect, DT_NOPREFIX|DT_CALCRECT);
  242.                 }
  243.                 DeleteDC(hDC);
  244.             }
  245.             if (rect.right < ResultRect.right || rect.bottom < ResultRect.bottom)
  246.             {
  247.                 CFlexWnd::s_ToolTip.SetToolTipParent(GetParent(m_hWnd));
  248.                 TOOLTIPINITPARAM ttip;
  249.                 ttip.hWndParent = GetParent(m_hWnd);
  250.                 ttip.iSBWidth = 0;
  251.                 ttip.dwID = 0;
  252.                 ttip.hWndNotify = m_hWnd;
  253.                 ttip.tszCaption = m_ListBox.GetSelText();
  254.                 CFlexToolTip::UpdateToolTipParam(ttip);
  255.             }
  256.             Notify(FCBN_MOUSEOVER);
  257.  
  258.         case WM_LBUTTONUP:
  259.         case WM_LBUTTONDOWN:
  260.         case WM_RBUTTONUP:
  261.         case WM_RBUTTONDOWN:
  262.         case WM_LBUTTONDBLCLK:
  263.         case WM_RBUTTONDBLCLK:
  264.             if (msg == WM_LBUTTONDOWN)
  265.             {
  266.                 HWND hWndParent;
  267.                 hWndParent = GetParent(hWnd);
  268.                 SendMessage(hWndParent, WM_UNHIGHLIGHT, 0, 0);  // Send click message to page to unhighlight callout
  269.             }
  270.             GetClientRect(&wrect);
  271.             point.x = int(LOWORD(lParam));
  272.             point.y = int(HIWORD(lParam));
  273.             bWithin = PtInRect(&wrect, point);
  274.             break;
  275.         case WM_TIMER:
  276.         case WM_CAPTURECHANGED:
  277.             break;
  278.         default:
  279.             return CFlexWnd::WndProc(hWnd, msg, wParam, lParam);
  280.     }
  281.  
  282.     switch (msg)
  283.     {
  284.         case WM_LBUTTONDOWN:
  285.             if (!GetReadOnly())
  286.                 StateEvent(bWithin ? FCBSE_DOWN : FCBSE_DOWNOFF);
  287.             break;
  288.  
  289.         case WM_LBUTTONUP:
  290.             if (!GetReadOnly())
  291.                 StateEvent(bWithin ? FCBSE_UPBOX : FCBSE_UPOFF);
  292.             break;
  293.     }
  294.  
  295.     return 0;
  296. }
  297.  
  298. RECT CFlexComboBox::GetListBoxRect()
  299. {
  300.     HWND hParent = GetParent(m_hWnd);
  301.     RECT rect;
  302.     GetClientRect(&rect);
  303.     BOOL bRet = ClientToScreen(m_hWnd, &rect);
  304.     BOOL bRet2 = ScreenToClient(hParent, &rect);
  305.  
  306.     RECT lrect = m_rect;
  307.     lrect.top = rect.bottom;
  308.     lrect.right -= 12;  // UNDONE: remove this line when the clipping is working properly (scroll bars don't appear above other windows)
  309.  
  310.     return lrect;
  311. }
  312.  
  313. void CFlexComboBox::DoSel()
  314. {
  315.     if (m_bInSelMode)
  316.         return;
  317.     
  318.     if (m_hWnd == NULL)
  319.         return;
  320.  
  321.     FLEXLISTBOXCREATESTRUCT cs;
  322.     cs.dwSize = sizeof(FLEXLISTBOXCREATESTRUCT);
  323.     cs.dwFlags = m_dwListBoxFlags;
  324.     cs.hWndParent = GetParent(m_hWnd);
  325.     cs.hWndNotify = m_hWnd;
  326.     cs.bVisible = FALSE;
  327.     cs.rect = GetListBoxRect();
  328.     cs.hFont = m_hFont;
  329.     cs.rgbText = m_rgbText;
  330.     cs.rgbBk = m_rgbBk;
  331.     cs.rgbSelText = m_rgbSelText;
  332.     cs.rgbSelBk = m_rgbSelBk;
  333.     cs.rgbFill = m_rgbFill;
  334.     cs.rgbLine = m_rgbLine;
  335.     cs.nSBWidth = m_nSBWidth;
  336.  
  337.     m_OldSel = m_ListBox.GetSel();
  338.  
  339.     m_bInSelMode = m_ListBox.Create(&cs);
  340.     if (m_bInSelMode)
  341.         SetWindowPos(m_ListBox.m_hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
  342. }
  343.  
  344. void CFlexComboBox::Notify(int code)
  345. {
  346.     if (!m_hWndNotify)
  347.         return;
  348.  
  349.     SendMessage(m_hWndNotify, WM_FLEXCOMBOBOX,
  350.         (WPARAM)code, (LPARAM)(LPVOID)this);
  351. }
  352.  
  353. RECT CFlexComboBox::GetRect(const RECT &rect)
  354. {
  355.     int h = GetTextHeight(m_hFont);
  356.     RECT ret = {rect.left, rect.top, rect.right, rect.top + h + 2};
  357.     return ret;
  358. }
  359.  
  360. RECT CFlexComboBox::GetRect()
  361. {
  362.     RECT rect;
  363.     GetClientRect(&rect);
  364.     return GetRect(rect);
  365. }
  366.  
  367. void CFlexComboBox::SetFont(HFONT hFont)
  368. {
  369.     m_hFont = hFont;
  370.  
  371.     if (m_hWnd == NULL)
  372.         return;
  373.  
  374.     Invalidate();
  375.     SetRect();
  376. }
  377.  
  378. void CFlexComboBox::SetRect()
  379. {
  380.     if (m_hWnd == NULL)
  381.         return;
  382.  
  383.     RECT rect = GetRect();
  384.     SetWindowPos(m_hWnd, NULL, rect.left, rect.top, rect.right, rect.bottom, SWP_NOZORDER | SWP_NOMOVE);
  385. }
  386.  
  387. void CFlexComboBox::SetColors(COLORREF text, COLORREF bk, COLORREF seltext, COLORREF selbk, COLORREF fill, COLORREF line)
  388. {
  389.     m_rgbText = text;
  390.     m_rgbBk = bk;
  391.     m_rgbSelText = seltext;
  392.     m_rgbSelBk = selbk;
  393.     m_rgbFill = fill;
  394.     m_rgbLine = line;
  395.     Invalidate();
  396. }
  397.  
  398. void CFlexComboBox::StateEvent(FCBSTATEEVENT e)
  399. {
  400.     if (e == FCBSE_DOWNOFF)
  401.     {
  402.         SetState(FCBS_CANCEL);
  403.         return;
  404.     }
  405.  
  406.     switch (m_eCurState)
  407.     {
  408.         case FCBS_CLOSED:
  409.             if (e == FCBSE_DOWN)
  410.                 SetState(FCBS_OPENDOWN);
  411.             break;
  412.  
  413.         case FCBS_OPENDOWN:
  414.             switch (e)
  415.             {
  416.                 case FCBSE_UPLIST:
  417.                     SetState(FCBS_SELECT);
  418.                     break;
  419.                 case FCBSE_UPBOX:
  420.                     SetState(FCBS_OPENUP);
  421.                     break;
  422.                 case FCBSE_UPOFF:
  423.                     SetState(FCBS_CANCEL);
  424.                     break;
  425.             }
  426.  
  427.         case FCBS_OPENUP:
  428.             if (e == FCBSE_DOWN)
  429.                 SetState(FCBS_OPENDOWN);
  430.             break;
  431.  
  432.         default:
  433.             assert(0);
  434.             return;
  435.     }
  436. }
  437.  
  438. void CFlexComboBox::SetState(FCBSTATE s)
  439. {
  440.     FCBSTATE eOldState = m_eCurState;
  441.     m_eCurState = s;
  442.  
  443.     switch (s)
  444.     {
  445.         case FCBS_OPENUP:
  446.             if (eOldState == FCBS_CLOSED)
  447.                 DoSel();
  448.             return;
  449.  
  450.         case FCBS_OPENDOWN:
  451.             if (eOldState == FCBS_CLOSED)
  452.                 DoSel();
  453.             m_ListBox.StartSel();
  454.             return;
  455.  
  456.         case FCBS_CANCEL:
  457.             m_ListBox.SetSel(m_OldSel);
  458.             CFlexWnd::s_ToolTip.SetEnable(FALSE);
  459.             SetState(FCBS_CLOSED);
  460.             return;
  461.  
  462.         case FCBS_SELECT:
  463.             CFlexWnd::s_ToolTip.SetEnable(FALSE);
  464.             Invalidate();
  465.             Notify(FCBN_SELCHANGE);
  466.             SetState(FCBS_CLOSED);
  467.             return;
  468.  
  469.         case FCBS_CLOSED:
  470.             if (eOldState != FCBS_CLOSED)
  471.                 m_ListBox.Destroy();
  472.             m_bInSelMode = FALSE;
  473.             Invalidate();
  474.             return;
  475.     }
  476. }
  477.